import { delay } from "../lib/delay";

/**
 * 通过这个对象，可以让 Spider 进行执行
 */
export class TaskController {
    // 所有任务
    private tasks: Task[] = [];



    /** 创建一个任务 */
    public createTask(url: string | URL, immediate: boolean = false) {
        if (url instanceof URL) {
            url = URL.toString();
        }
        const taskItem = new Task(url);
        this.addTask(taskItem, immediate);
    }

    /** 添加一个任务 */
    public addTask(taskItem: Task, immediate: boolean = false) {
        if (immediate) {
            this.tasks.unshift(taskItem)
        } else {
            this.tasks.push(taskItem);
        }
        taskItem._setController(this);
    }


    /** 获取下一个任务(这个任务会被弹出) */
    public async waitNextTask() {
        // 如果没有任务 则等短时间在问一次
        while (!this.hasNextTask()) {
            await delay(100);
        }
        return this.tasks.pop();
    }
    /**
     * 判断是否还有任务
     * @returns 
     */
    private hasNextTask() {
        return this.tasks.length > 0;
    }
}

export class Task {
    /** 最大重试次数 */
    public static maxRepeatCount = parseInt(process.env.maxRepeatCount as string);
    /** 自己所属的控制器 */
    private taskController?: TaskController

    constructor(
        /** 爬取的地址 */
        public url: string,
        /** 重复执行的次数 */
        public repeat_count: number = 0
    ) { }

    /**
     * 设置自己所属的控制器
     * @param taskController 
     */
    public _setController(taskController: TaskController) {
        this.taskController = taskController;
    }

    /**
     * 重新执行这个任务
     * 如果这个任务重复执行的次数超过阈值(10次)，则不会重复执行
     * 如果 immediate 为真，则在下一个任务重新执行这个任务，反之则在所有任务的最后执行.就像列队那样。
     * @param immediate 立即执行，默认是 false
     */
    public repeat(immediate: boolean = false) {
        if (this.repeat_count > Task.maxRepeatCount) {
            console.warn(`${this.url}任务重试${this.repeat_count}次，已丢弃。`);
            return;// 超出最大限制，不在执行
        }

        if (!this.taskController) {
            console.warn("该任务没有所属控制器，重复操作是失败的。")
            return;
        }

        // 通知控制器将自己当作新任务添加进去
        this.taskController.addTask(this, immediate);

        this.repeat_count += 1; //重试次数 + 1
    }

}